package com.heima.search.service.impl;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.UserSearchDto;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.ArticleSearchService;
import com.heima.search.utils.AppThreadLocalUtil;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ArticleSearchServiceImpl implements ArticleSearchService {

    @Resource
    private RestHighLevelClient client;

    @Resource
    private ApUserSearchService apUserSearchService;

    /**
     * es搜索
     *
     * @param userSearchDto
     * @return
     */
    @Override
    public ResponseResult search(UserSearchDto userSearchDto) {
        try {
            //1.参数校验
            if (userSearchDto == null || StringUtils.isEmpty(userSearchDto.getSearchWords())) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
            }

            //异步调用，保存搜索记录
            //只有在用户登录的情况下 , 而且是第一次搜索的时候才需要保存搜索历史记录
            Long userId = AppThreadLocalUtil.getId();
            if (userId != null && userSearchDto.getFromIndex()==0) {
                apUserSearchService.insert(userSearchDto.getSearchWords(),userId);
            }

            //2.创建请求对象
            SearchRequest request = new SearchRequest("app_article_info");
            //3.封装DSL语句
            //3.1查询条件，title 关键字匹配    publishTime 范围匹配
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            //3.1.1关键字匹配
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(userSearchDto.getSearchWords(), "title", "content"));
            //3.1.2范围匹配
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("publishTime").lt(userSearchDto.getMinBehotTime()));
            request.source().query(boolQueryBuilder);
            //3.2排序
            request.source().sort("publishTime", SortOrder.DESC);
            //3.3高亮
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("title");
            highlightBuilder.preTags("<font style='color:red; font-size: inherit;'>");
            highlightBuilder.postTags("</font>");
            request.source().highlighter(highlightBuilder);
            //3.4分页
            request.source().size(10);
            //4.发送请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            //5.结果解析
            SearchHits hits = response.getHits();
            //5.1总条数
            long total = hits.getTotalHits().value;
            //5.2数据列表
            SearchHit[] hits1 = hits.getHits();
            List<Map> list = Arrays.stream(hits1).map(searchHit -> {
                //获取文档数据
                String json = searchHit.getSourceAsString();
                Map map = JSON.parseObject(json, Map.class);
                //获取高亮数据
                Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                if (MapUtil.isNotEmpty(highlightFields)) {
                    HighlightField field = highlightFields.get("title");
                    if (field != null) {
                        Text[] fragments = field.getFragments();
                        map.put("h_title", StringUtils.join(fragments, ","));
                    }
                } else {
                    map.put("h_title", map.get("title"));
                }
                return map;
            }).collect(Collectors.toList());

            return ResponseResult.okResult(list);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Override
    public void save(SearchArticleVo searchArticleVo) {

        try {
            IndexRequest request = new IndexRequest("app_article_info").id(searchArticleVo.getId().toString());
            request.source(JSON.toJSONString(searchArticleVo), XContentType.JSON);
            client.index(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
